/*
 * Copyright (c) 2025 Industrial Software Feature Database
 */
package com.comac.ins.isfd.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.comac.ins.common.core.exception.ServiceException;
import com.comac.ins.common.core.utils.MapstructUtils;
import com.comac.ins.common.core.utils.StreamUtils;
import com.comac.ins.common.core.utils.StringUtils;
import com.comac.ins.common.core.utils.file.FileUtils;
import com.comac.ins.common.mybatis.core.page.PageQuery;
import com.comac.ins.common.mybatis.core.page.TableDataInfo;
import com.comac.ins.common.oss.core.OssClient;
import com.comac.ins.common.oss.entity.UploadResult;
import com.comac.ins.common.oss.enumd.AccessPolicyType;
import com.comac.ins.common.oss.factory.OssFactory;
import com.comac.ins.isfd.domain.IsfdResult;
import com.comac.ins.isfd.domain.bo.IsfdResultBo;
import com.comac.ins.isfd.domain.vo.IsfdResultVo;
import com.comac.ins.isfd.domain.vo.ResultCountObjectVo;

import com.comac.ins.isfd.mapper.ResultMapper;
import com.comac.ins.isfd.service.IIsfdResultService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 结果库service层接口实现层
 *
 * @author zhouyaoixn
 * @date 2024-7-11
 */
@RequiredArgsConstructor
@Service
public class IsfdResultServiceImpl implements IIsfdResultService {

    private final ResultMapper resultMapper;

    @Override
    public List<ResultCountObjectVo> listCount() {
        List<ResultCountObjectVo> result = new ArrayList<>();
        QueryWrapper queryWrapper = new QueryWrapper<>();
        queryWrapper.select("applicable_result", "COUNT(*) as total_count");
        queryWrapper.groupBy("applicable_result");
        List<Map<String, Object>> list = resultMapper.selectMaps(queryWrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach((m -> {
                result.add(new ResultCountObjectVo((String) m.get("applicable_result"), (Long) m.get("total_count")));
            }));
        }
        return result;
    }


    @Override
    public IsfdResultVo getById(Long resultId) {
        return resultMapper.selectVoById(resultId);
    }

    @Override
    public TableDataInfo<IsfdResultVo> queryPageList(IsfdResultBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<IsfdResult> lqw = buildQueryWrapper(bo, pageQuery);
        Page<IsfdResultVo> result = resultMapper.selectVoPage(pageQuery.build(), lqw);
        List<IsfdResultVo> filterResult = StreamUtils.toList(result.getRecords(), this::matchingUrl);
        result.setRecords(filterResult);
        return TableDataInfo.build(result);
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            // todo
            // 做一些业务上的校验,判断是否需要校验
        }
        List<IsfdResult> list = resultMapper.selectBatchIds(ids);
        for (IsfdResult isfdResult : list) {
            OssClient storage = OssFactory.instance(isfdResult.getService());
            storage.delete(isfdResult.getUrl());
        }
        return resultMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public IsfdResultVo save(MultipartFile file, IsfdResultBo isfdResultBo) {
        String originalFileName = file.getOriginalFilename();
        String suffix = StringUtils.substring(originalFileName, originalFileName.lastIndexOf("."), originalFileName.length());
        OssClient storage = OssFactory.instance();
        UploadResult uploadResult;
        try {
            uploadResult = storage.uploadSuffix(file.getBytes(), suffix);
        } catch (IOException e) {
            throw new ServiceException(e.getMessage());
        }
        // 保存文件信息
        return saveResultDetail(originalFileName, storage.getConfigKey(), uploadResult, isfdResultBo);
    }

    @NotNull
    private IsfdResultVo saveResultDetail(String originalfileName, String configKey,
                                        UploadResult uploadResult, IsfdResultBo isfdResultBo) {
        IsfdResult isfdResult = new IsfdResult();
        isfdResult.setUrl(uploadResult.getUrl());
        isfdResult.setFileName(uploadResult.getFilename());
        isfdResult.setOriginalName(originalfileName);
        isfdResult.setService(configKey);
        isfdResult.setResultName(isfdResultBo.getResultName());
        isfdResult.setResultType(isfdResultBo.getResultType());
        isfdResult.setApplicableResult(isfdResultBo.getApplicableResult());
        isfdResult.setResultSeries(isfdResultBo.getResultSeries());
        isfdResult.setLoadConditions(isfdResultBo.getLoadConditions());
        isfdResult.setResultScope(isfdResultBo.getResultScope());
        resultMapper.insert(isfdResult);
        IsfdResultVo isfdResultVo = MapstructUtils.convert(isfdResult, IsfdResultVo.class);
        return this.matchingUrl(isfdResultVo);
    }

    @Override
    public void download(Long resultId, HttpServletResponse response) throws IOException {
        IsfdResultVo isfdResultVo = this.getById(resultId);
        if (ObjectUtil.isNull(isfdResultVo)) {
            throw new ServiceException("文件数据不存在!");
        }
        FileUtils.setAttachmentResponseHeader(response, isfdResultVo.getOriginalName());
        response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
        OssClient storage = OssFactory.instance(isfdResultVo.getService());
        long contentLength = storage.download(isfdResultVo.getFileName(), response.getOutputStream());
        response.setContentLengthLong(contentLength);
    }

    @Override
    public void update(IsfdResultBo isfdResultBo) {
        LambdaUpdateWrapper<IsfdResult> updateWrapper = new LambdaUpdateWrapper();
        updateWrapper.eq(IsfdResult::getResultId,isfdResultBo.getResultId());
        updateWrapper.set(IsfdResult::getApplicableResult,isfdResultBo.getApplicableResult());
        updateWrapper.set(IsfdResult::getResultScope,isfdResultBo.getResultScope());
        updateWrapper.set(IsfdResult::getResultSeries,isfdResultBo.getResultSeries());
        updateWrapper.set(IsfdResult::getLoadConditions,isfdResultBo.getLoadConditions());
        resultMapper.update(updateWrapper);

    }


    private LambdaQueryWrapper<IsfdResult> buildQueryWrapper(IsfdResultBo bo, PageQuery pageQuery) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<IsfdResult> lqw = Wrappers.lambdaQuery();
        //按层级查询 先看第1层是否为空
        lqw.eq(StringUtils.isNotBlank(bo.getApplicableResult()), IsfdResult::getApplicableResult,bo.getApplicableResult());
        lqw.eq(StringUtils.isNotBlank(bo.getResultSeries()), IsfdResult::getResultSeries, bo.getResultSeries());
        lqw.eq(StringUtils.isNotBlank(bo.getLoadConditions()), IsfdResult::getLoadConditions, bo.getLoadConditions());
        lqw.eq(StringUtils.isNotBlank(bo.getResultScope()), IsfdResult::getResultScope, bo.getResultScope());
        lqw.like(StringUtils.isNotBlank(bo.getResultName()), IsfdResult::getResultName, bo.getResultName());
        lqw.like(StringUtils.isNotBlank(bo.getResultType()), IsfdResult::getResultType, bo.getResultType());
        lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
            IsfdResult::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
        return lqw;
    }


    private IsfdResultVo matchingUrl(IsfdResultVo resultVo) {
        OssClient storage = OssFactory.instance(resultVo.getService());
        // 仅修改桶类型为 private 的URL，临时URL时长为120s
        if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) {
            resultVo.setUrl(storage.getPrivateUrl(resultVo.getFileName(), 120));
        }
        return resultVo;
    }
}
